<?php

namespace App\Http\Controllers\FileControllers;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\Models\File;
use App\Models\DataTableModel\Folder;
use Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use ZipArchive;

class FolderFileDownloadControllers extends Controller
{
    // 下载文件  
    public function downloadFile(Request $request)
    {
        $fileId = $request->input('fileId');
        $source = $request->input('source');
        try {
            if ($source === 'file') {
                $file = File::find($fileId);

                if (!$file) {
                    abort(404, '文件未找到');
                }
                // 获取文件路径,根据文件夹id查找父文件夹id，直到folder表中parent_folder_id=null
                // 用while循环，每次获取到父文件夹id，拼接文件路径
                // 拼接文件路径
                $filePath = $file->file_name; // 用来存储完整路径的变量
                $pr_id = $file->file_parent_folder_id; // 保存当前层级父文件夹id
                while ($pr_id != null) {
                    $pr_folder = Folder::find($pr_id);
                    $filePath = $pr_folder->folder_name . '/' . $filePath;
                    $pr_id = $pr_folder->parent_folder_id;
                }
                $filePath = '/' . $filePath;

                // $filePath = storage_path('app/public/UserNetworkDiskFile/' . $folder->folder_name . '/' . $file->file_path);  
                $filePath = storage_path('app/public/UserNetworkDiskFile' . $filePath);

                if (!file_exists($filePath)) {
                    abort(404, '文件不存在');
                }
                $rawFileName = $file->file_name; 
                $encodedFileName = urlencode($rawFileName); // 对文件名进行URL编码  
                $headers = [
                    'Content-Type' => $file->file_type,
                    "Content-Disposition" => "attachment; filename=UTF-8''" . $rawFileName
                ];
                return response()->download($filePath, $rawFileName, $headers);
            } elseif ($source === 'folder') {
                // 根据传进来的folder_id获取文件夹信息
                $folder = Folder::find($fileId);
                // 获取文件夹name
                $folderName = $folder->folder_name;
                // 根据文件夹父文件夹id循环查找文件夹name，拼接，直到folder表中parent_folder_id=null

                // 拼接文件夹路径
                $folderPath = $folderName; // 用来存储完整路径的变量
                $pr_id = $folder->parent_folder_id; // 保存当前层级父文件夹id
                while ($pr_id != null) {
                    $pr_folder = Folder::find($pr_id);
                    $folderPath = $pr_folder->folder_name . '/' . $folderPath;
                    $pr_id = $pr_folder->parent_folder_id;
                }
                $folderPath = '/' . $folderPath;

                // 拼接文件夹路径
                $filePath = storage_path('app/public/UserNetworkDiskFile' . $folderPath);
                if (!file_exists($filePath)) {
                    abort(404, '文件夹不存在');
                }
                // 检查文件夹是否为空  
                if (!$this->isFolderEmpty($filePath)) {
                    // 文件夹路径    
                    $zipFilePath = storage_path('app/public/UserNetworkDiskFile/downloads/' . $folderName . '.zip');
                    // 创建一个ZipArchive实例并打开zip文件以供写入    
                    $zip = new ZipArchive();
                    if ($zip->open($zipFilePath, ZipArchive::CREATE | ZipArchive::OVERWRITE) !== TRUE) {
                        abort(500, '无法创建zip文件');
                    }
                    // 递归添加文件夹内容到zip文件  
                    function addFolderToZip($folder, $locationInZip = '', &$zip)
                    {
                        $dir = opendir($folder);
                        // 遍历文件夹中的文件和子文件夹  
                        while (($file = readdir($dir)) !== false) {
                            if ($file != '.' && $file != '..') {
                                $filePath = $folder . '/' . $file;
                                // 如果是文件夹，则递归处理  
                                if (is_dir($filePath)) {
                                    addFolderToZip($filePath, $locationInZip . $file . '/', $zip);
                                } else {
                                    // 如果是文件，则添加到zip中  
                                    $zip->addFile($filePath, $locationInZip . $file);
                                }
                            }
                        }
                        closedir($dir);
                        dump($dir);
                    }
                    // 调用递归函数来添加文件夹内容  
                    addFolderToZip($filePath, '', $zip);
                    // 关闭zip文件  
                    $zip->close();

                    // 提供下载的zip文件  
                    return response()->download($zipFilePath, $folderName . '.zip')->deleteFileAfterSend(true);
                } else {
                    // 文件夹为空，返回一个友好消息  
                    return response()->json(['message' => '文件夹为空，没有内容可以下载'], 200);
                }
            }
        } catch (ModelNotFoundException $e) {
            // 捕获其他类型的异常  
            if (config('app.debug')) {
                // 在开发环境中，返回详细的错误信息并记录到日志  
                // \Log::error('检索文件时出错: ' . $e->getMessage() . "\n" . $e->getTraceAsString());  
                return response()->json([
                    'message' => '检索文件时出错',
                    'error' => [
                        'message' => $e->getMessage(), // 具体的错误消息  
                        'file' => $e->getFile(), // 错误发生的文件  
                        'line' => $e->getLine(), // 错误发生的行号  
                        'trace' => explode("\n", $e->getTraceAsString()), // 完整的堆栈跟踪，仅用于开发环境  
                    ],
                    'code' => $e->getCode(), // 错误代码  
                ], 500);
            } else {
                // 在生产环境中，仅记录错误到日志并返回通用的错误响应  
                // \Log::error('检索文件时出错: ' . $e->getMessage());  
                return response()->json(['message' => '文件或文件夹未找到'], 404);
            }
        } catch (\Exception $e) {
            // 捕获其他类型的异常  
            if (config('app.debug')) {
                // 在开发环境中，返回详细的错误信息并记录到日志  
                // \Log::error('检索文件时出错: ' . $e->getMessage() . "\n" . $e->getTraceAsString());  
                return response()->json([
                    'message' => '检索文件时出错',
                    'error' => [
                        'message' => $e->getMessage(), // 具体的错误消息  
                        'file' => $e->getFile(), // 错误发生的文件  
                        'line' => $e->getLine(), // 错误发生的行号  
                        'trace' => explode("\n", $e->getTraceAsString()), // 完整的堆栈跟踪，仅用于开发环境  
                    ],
                    'code' => $e->getCode(), // 错误代码  
                ], 500);
            } else {
                // 在生产环境中，仅记录错误到日志并返回通用的错误响应  
                // \Log::error('检索文件时出错: ' . $e->getMessage());  
                return response()->json(['message' => '服务器内部错误，请稍后再试'], 500);
            }
        }
    }
    // 批量下载
    public function bulkDownload(Request $request)
    {
        try {
            $fileIds = $request->input('fileIds');
            if (!is_array($fileIds) || empty($fileIds)) {
                abort(400, 'Invalid file IDs');
            }
            $zip = new ZipArchive();
            $zipFilename = "bulk_download_" . time() . ".zip";
            $zipPath = storage_path('app/public/UserNetworkDiskFile/downloads/' . $zipFilename);

            if ($zip->open($zipPath, ZipArchive::CREATE) !== TRUE) {
                abort(500, '无法打开zip文件');
            }

            foreach ($fileIds as $fileId) {
                $file = File::find($fileId);
                if (!$file) {
                    continue; // 或者选择记录错误、跳过该文件等  
                }

                $file = File::find($fileId);

                if (!$file) {
                    abort(404, '文件未找到');
                }

                // 获取到用户id
                $userId = auth()->user()->id;
                // 根据获取到的用户id和parent_folder_id为null在folder表中查询根目录文件夹
                $folder = Folder::where('id', $userId)->whereNull('parent_folder_id')->first();
                $filePath = storage_path('app/public/UserNetworkDiskFile/' . $folder->folder_name . '/' . $file->file_path); // 假设文件存储在这个路径下  
                if (file_exists($filePath)) {
                    $zip->addFile($filePath, basename($filePath));
                }
            }

            $zip->close();

            // 提供下载的zip文件  
            return response()->download($zipPath, $zipFilename)->deleteFileAfterSend(true);
        } catch (ModelNotFoundException $e) {
            // 捕获其他类型的异常  
            if (config('app.debug')) {
                // 在开发环境中，返回详细的错误信息并记录到日志  
                // \Log::error('检索文件时出错: ' . $e->getMessage() . "\n" . $e->getTraceAsString());  
                return response()->json([
                    'message' => '检索文件时出错',
                    'error' => [
                        'message' => $e->getMessage(), // 具体的错误消息  
                        'file' => $e->getFile(), // 错误发生的文件  
                        'line' => $e->getLine(), // 错误发生的行号  
                        'trace' => explode("\n", $e->getTraceAsString()), // 完整的堆栈跟踪，仅用于开发环境  
                    ],
                    'code' => $e->getCode(), // 错误代码  
                ], 500);
            } else {
                // 在生产环境中，仅记录错误到日志并返回通用的错误响应  
                // \Log::error('检索文件时出错: ' . $e->getMessage());  
                return response()->json(['message' => '服务器内部错误，请稍后再试'], 500);
            }
        } catch (\Exception $e) {
            // 捕获其他类型的异常  
            if (config('app.debug')) {
                // 在开发环境中，返回详细的错误信息并记录到日志  
                // \Log::error('检索文件时出错: ' . $e->getMessage() . "\n" . $e->getTraceAsString());  
                return response()->json([
                    'message' => '检索文件时出错',
                    'error' => [
                        'message' => $e->getMessage(), // 具体的错误消息  
                        'file' => $e->getFile(), // 错误发生的文件  
                        'line' => $e->getLine(), // 错误发生的行号  
                        'trace' => explode("\n", $e->getTraceAsString()), // 完整的堆栈跟踪，仅用于开发环境  
                    ],
                    'code' => $e->getCode(), // 错误代码  
                ], 500);
            } else {
                // 在生产环境中，仅记录错误到日志并返回通用的错误响应  
                // \Log::error('检索文件时出错: ' . $e->getMessage());  
                return response()->json(['message' => '服务器内部错误，请稍后再试'], 500);
            }
        }
    }



    // 检查文件夹是否为空的辅助函数  
    function isFolderEmpty($folderPath)
    {
        $dir = opendir($folderPath);

        // 跳过当前目录和上级目录  
        while (($file = readdir($dir)) !== false) {
            if ($file != '.' && $file != '..') {
                closedir($dir);
                return false; // 文件夹不为空  
            }
        }
        closedir($dir);
        return true; // 文件夹为空  
    }
}
